package rexsee.barcode;

import java.util.Hashtable;

import android.graphics.PixelFormat;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.widget.Toast;

import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;

public class DecodeHandler extends Handler {

	public static final int MESSAGE_AUTO_FOCUS = 0;
	public static final int MESSAGE_RESTART_PREVIEW = 1;
	public static final int MESSAGE_DECODE_SUCCEEDED = 2;
	public static final int MESSAGE_DECODE_FAILED = 3;
	public static final int MESSAGE_DECODE = 4;
	public static final int MESSAGE_QUIT = 5;

	private final BarcodeCaptureDialog mDialog;
	private final MultiFormatReader multiFormatReader;

	public DecodeHandler(BarcodeCaptureDialog dialog, Hashtable<DecodeHintType, Object> hints) {
		multiFormatReader = new MultiFormatReader();
		multiFormatReader.setHints(hints);
		mDialog = dialog;
	}

	@Override
	public void handleMessage(Message message) {
		if (message.what == MESSAGE_DECODE) {
			Result rawResult = null;
			PlanarYUVLuminanceSource source = null;
			byte[] data = (byte[]) message.obj;
			int width = message.arg1, height = message.arg2;
			switch (mDialog.mPreviewFormat) {
				case PixelFormat.YCbCr_420_SP :
					// This is the standard Android format which all devices are REQUIRED to support. In theory, it's the only one we should ever care about.
				case PixelFormat.YCbCr_422_SP :
					// This format has never been seen in the wild, but is compatible as we only care about the Y channel, so allow it.
					source = new PlanarYUVLuminanceSource(data, width, height, mDialog.mFramingRectInPreview.left, mDialog.mFramingRectInPreview.top, mDialog.mFramingRectInPreview.width(), mDialog.mFramingRectInPreview.height());
				default :
					// The Samsung Moment incorrectly uses this variant instead of the 'sp' version. Fortunately, it too has all the Y data up front, so we can read it.
					if ("yuv420p".equals(mDialog.mPreviewFormatString)) {
						source = new PlanarYUVLuminanceSource(data, width, height, mDialog.mFramingRectInPreview.left, mDialog.mFramingRectInPreview.top, mDialog.mFramingRectInPreview.width(), mDialog.mFramingRectInPreview.height());
					}
			}
			if (source == null) {
				Toast.makeText(mDialog.getContext(), "Unsupported picture format: " + mDialog.mPreviewFormat + '/' + mDialog.mPreviewFormatString, Toast.LENGTH_LONG).show();
				mDialog.dismissDialog(null, null, null, null, null, null);
				return;
			}
			BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
			try {
				rawResult = multiFormatReader.decodeWithState(bitmap);
			} catch (Exception e) {
			} finally {
				multiFormatReader.reset();
			}
			if (rawResult != null) {
				Message msg = Message.obtain(mDialog.mCaptureHandler, MESSAGE_DECODE_SUCCEEDED, rawResult);
				Bundle bundle = new Bundle();
				bundle.putParcelable(DecodeThread.BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());
				msg.setData(bundle);
				msg.sendToTarget();
			} else {
				Message msg = Message.obtain(mDialog.mCaptureHandler, MESSAGE_DECODE_FAILED);
				msg.sendToTarget();
			}
		} else if (message.what == MESSAGE_QUIT) {
			Looper.myLooper().quit();
		}
	}

}
